package com.softer.wxzj.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.softer.wxzj.common.entity.CommonResult;
import com.softer.wxzj.common.entity.Page;
import com.softer.wxzj.common.enums.MessageEnum;
import com.softer.wxzj.common.enums.NumStrEnum;
import com.softer.wxzj.common.enums.NumberEnum;
import com.softer.wxzj.common.enums.ShiroResultEnum;
import com.softer.wxzj.common.error.CourseException;
import com.softer.wxzj.common.flow.enums.FlowStateEnum;
import com.softer.wxzj.common.flow.enums.FlowTypeEnum;
import com.softer.wxzj.common.flow.util.FlowAddAuditUtil;
import com.softer.wxzj.common.flow.util.FlowAuditUtil;
import com.softer.wxzj.common.flow.util.Result;
import com.softer.wxzj.common.util.OperUtil;
import com.softer.wxzj.common.util.ShiroUserUtil;
import com.softer.wxzj.common.util.StringUtils;
import com.softer.wxzj.common.util.UUIDUtil;
import com.softer.wxzj.entity.ExpPayReq;
import com.softer.wxzj.entity.ExpProjectReq;
import com.softer.wxzj.entity.ExpRevocation;
import com.softer.wxzj.entity.SysOperator;
import com.softer.wxzj.mapper.*;
import com.softer.wxzj.service.ExpRevocationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author Gong Zhiyang
 * @date 2019/8/10
 */
@Service
public class ExpRevocationServiceImpl implements ExpRevocationService {
    @Autowired
    private ExpRevocationMapper expRevocationMapper;
    @Autowired
    private FlowAddAuditUtil flowAddAuditUtil;
    @Autowired
    private ExpProjectReqMapper expProjectReqMapper;
    @Autowired
    private ExpPayReqMapper expPayReqMapper;
    @Autowired
    private ExpPayReqDetailMapper expPayReqDetailMapper;
    @Autowired
    private AccKeepAccountMapper accKeepAccountMapper;
    @Autowired
    private FlowAuditUtil flowUtil;
    @Autowired
    private Result result;
    @Autowired
    private OperUtil zoneCodeUtil;
    @Autowired
    private SysOperatorMapper sysOperatorMapper;

    /**
     * 维修项目撤销列表
     *
     * @param page          分页实体
     * @param expRevocation 查询实体
     * @return 列表
     */
    @Override
    public PageInfo<ExpRevocation> getProjectList(Page page, ExpRevocation expRevocation) {
        String zoneCode = zoneCodeUtil.getZoneCode();
        expRevocation.setZoneCode(zoneCode);
        List<ExpRevocation> list;
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        if (StringUtils.isNotEmpty(expRevocation.getFuzzy())) {
            //模糊查询
            list = expRevocationMapper.fuzzyProjectList(expRevocation);
        } else {
            //精确查询
            list = expRevocationMapper.getProjectList(expRevocation);
        }
        String operName = ShiroUserUtil.getUser().getOperName();
        String date = LocalDate.now().toString();
        for (ExpRevocation exp : list) {
            exp.setRevocatPerson(operName);
            exp.setRevocatDate(date);
        }
        return new PageInfo<>(list);
    }

    /**
     * 项目撤销提交
     *
     * @param expRevocation 撤销实体
     *                      id 项目ID
     *                      revocatDate 撤销日期
     *                      revocatReason 撤销原因
     * @return 提交结果
     */
    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public CommonResult projectRevocation(ExpRevocation expRevocation) {
        String id = expRevocation.getId();
        ExpProjectReq expProjectReq = expProjectReqMapper.selectByPrimaryKey(id);
        if (StringUtils.isEmpty(expRevocation.getRevocatDate())) {
            expRevocation.setRevocatDate(LocalDate.now().toString());
        }
        String userName = setRevocation(expRevocation);
        //指定业务id和流程类型
        String initState = flowAddAuditUtil.initFlow(id, FlowTypeEnum.PROJECT_REVOCATION.getType(), null);
        if (StringUtils.isEmpty(initState)) {
            return CommonResult.ResponseResult(NumberEnum.ZERO.getNum(), "该业务正在撤销，禁止重复操作");
        }
        expProjectReqMapper.changeStep(id, NumStrEnum.NINE.getNum());
        if (String.valueOf(NumberEnum.TWO.getNum()).equals(initState)) {
            //审批流的最后一级，直接审核通过，将项目状态改为保存状态
            expProjectReq.setStep(initState);
            expProjectReq.setFlowState(String.valueOf(NumberEnum.ZERO.getNum()));
            expProjectReq.setModifier(userName);
            int num = expProjectReqMapper.updateByPrimaryKeySelective(expProjectReq);
            if (num == NumberEnum.ZERO.getNum()) {
                throw new CourseException(ShiroResultEnum.FAIL.getCode(), "更新业务失败");
            }
        }
        //增加一条撤销记录
        expRevocation.setProjectId(id);
        expRevocation.setCreater(userName);
        expRevocation.setModifier(userName);
        expRevocation.setType(NumStrEnum.ONE.getNum());
        expRevocation.setBudgSum(expProjectReq.getBudgSum());
        expRevocation.setReqDate(expProjectReq.getProreportDate());
        expRevocation.setGrantreqUser(expProjectReq.getProreportUser());
        return addExpRevocation(expRevocation, initState, "", "", expProjectReq);
    }

    /**
     * 拨款申请撤回列表
     *
     * @param page      分页实体
     * @param expPayReq 查询实体
     * @return 列表
     */
    @Override
    public PageInfo<ExpPayReq> getPayList(Page page, ExpPayReq expPayReq) {
        String zoneCode = zoneCodeUtil.getZoneCode();
        expPayReq.setZoneCode(zoneCode);
        List<ExpPayReq> list;
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        if (StringUtils.isNotEmpty(expPayReq.getFuzzy())) {
            //模糊查询
            list = expRevocationMapper.fuzzyPayList(expPayReq);
        } else {
            //精确查询
            list = expRevocationMapper.getPayList(expPayReq);
        }
        String operName = ShiroUserUtil.getUser().getOperName();
        String date = LocalDate.now().toString();
        for (ExpPayReq exp : list) {
            exp.setModifier(operName);
            exp.setStartTime(date);
        }
        return new PageInfo<>(list);
    }

    /**
     * 拨款申请撤销
     *
     * @param expRevocation 撤销实体
     *                      id 拨款申请ID
     *                      revocatDate 撤销日期
     *                      revocatReason 撤销原因
     * @return 提交结果
     */
    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public CommonResult payRevocation(ExpRevocation expRevocation) {
        expRevocation.setFlowState(String.valueOf(NumberEnum.TWO.getNum()));
        //拨款批次id
        String id = expRevocation.getId();
        ExpPayReq expPayReq = expPayReqMapper.selectByPrimaryKey(id);
        String step = expPayReq.getStep();
        String grantreqNum = expPayReq.getGrantreqNum();
        String busiNo = expPayReq.getPayNo();
        if (StringUtils.isNotEmpty(busiNo)) {
            accKeepAccountMapper.updateState(NumStrEnum.ZERO.getNum(), busiNo);
        }
        ExpProjectReq expProjectReq = expProjectReqMapper.selectByPrimaryKey(expPayReq.getReqId());
        if (expProjectReq.getPayCount() != expPayReq.getReqNum()) {
            int max = expPayReqMapper.maxPassNum(expPayReq.getReqId());
            if (max != expPayReq.getReqNum()) {
                throw new CourseException(ShiroResultEnum.FAIL.getCode(), "不是最后一次拨款，不能撤销");
            }
        }
        String userName = setRevocation(expRevocation);
        //指定业务id和流程类型
        String initState = flowAddAuditUtil.initFlow(id, FlowTypeEnum.PAY_REVOCATION.getType(), null);
        if (StringUtils.isEmpty(initState)) {
            return CommonResult.ResponseResult(NumberEnum.ZERO.getNum(), "该业务正在撤销，禁止重复操作");
        }
        //拨款撤销中,步骤 0保存 1申请 2新建（新建凭证） 4已验证 5银行记账 6申请通过 7申请失败 8拨款撤销
        expPayReqMapper.updateStep(id, NumStrEnum.EIGHT.getNum(), null);

        if (String.valueOf(NumberEnum.TWO.getNum()).equals(initState)) {
            //审批流的最后一级，直接审核通过，将拨款申请状态改为保存状态
            expPayReq.setStep(String.valueOf(NumberEnum.ZERO.getNum()));
            expPayReq.setFlowState(String.valueOf(NumberEnum.ZERO.getNum()));
            expPayReq.setModifier(userName);
            int num = expPayReqMapper.updateByPayReqCancel(expPayReq);
            expPayReqDetailMapper.deleteByPayReqId(expPayReq.getId());
            if (num == NumberEnum.ZERO.getNum()) {
                throw new CourseException(ShiroResultEnum.FAIL.getCode(), "更新业务失败");
            }
        }
        //增加一条撤销记录
        expRevocation.setProjectId(expPayReq.getReqId());
        expRevocation.setCreater(userName);
        expRevocation.setModifier(userName);
        expRevocation.setType(NumStrEnum.TWO.getNum());
        expRevocation.setPayName(expPayReq.getReqName());
        expRevocation.setPayAmount(expPayReq.getPayAmount());
        expRevocation.setReqDate(expPayReq.getGrantreqDate());
        expRevocation.setGrantreqUser(expPayReq.getGrantreqUser());
        return addExpRevocation(expRevocation, initState, grantreqNum, step, expProjectReq);

    }

    private String setRevocation(ExpRevocation expRevocation) {
        String userName = expRevocation.getOperNo();
        if (StringUtils.isEmpty(userName)) {
            userName = ShiroUserUtil.getUserName();
            expRevocation.setRevocatPerson(ShiroUserUtil.getUser().getOperName());
        } else {
            SysOperator sysOperator = sysOperatorMapper.getOperInfoByOperNo(userName);
            expRevocation.setRevocatPerson(sysOperator.getOperName());
        }
        return userName;
    }

    /**
     * 撤销查询列表
     *
     * @param page          分页实体
     * @param expRevocation 查询实体
     * @return 撤销列表
     */
    @Override
    public PageInfo<ExpRevocation> revocationSearch(Page page, ExpRevocation expRevocation) {
        String zoneCode = zoneCodeUtil.getZoneCode();
        expRevocation.setZoneCode(zoneCode);
        //撤销类型(项目状态)（1维修项目撤销，2拨款申请撤销）
        String type = expRevocation.getType();
        List<ExpRevocation> list = new ArrayList<>(8);
        if (StringUtils.isNotEmpty(type)) {
            PageHelper.startPage(page.getPageNum(), page.getPageSize());
            if (String.valueOf(NumberEnum.ONE.getNum()).equals(type)) {
                //查询维修项目撤销列表
                list = expRevocationMapper.revocationProject(expRevocation);
            } else if (String.valueOf(NumberEnum.TWO.getNum()).equals(type)) {
                //拨款申请撤销列表
                list = expRevocationMapper.revocationPay(expRevocation);
            }
        }
        return new PageInfo<>(list);
    }

    /**
     * 查询项目撤销审批列表
     *
     * @param page          分页实体
     * @param expRevocation 查询实体
     * @return 审批列表
     */
    @Override
    public PageInfo<ExpRevocation> getProjectAuditList(Page page, ExpRevocation expRevocation) {
        //查询业务
        Map<String, String> map = flowUtil.getBussIdAndZoneCodeByOperNo(FlowTypeEnum.PROJECT_REVOCATION.getType());
        List<ExpRevocation> list = new ArrayList<>();
        if (null != map) {
            result.select(map, expRevocation);
            PageHelper.startPage(page.getPageNum(), page.getPageSize());
            if (StringUtils.isNotEmpty(expRevocation.getFuzzy())) {
                //模糊查询
                list = expRevocationMapper.fuzzyProjectAuditList(expRevocation);
            } else {
                //精确查询
                list = expRevocationMapper.getProjectAuditList(expRevocation);
            }
        }
        return new PageInfo<>(list);
    }

    /**
     * 审核
     *
     * @param id      ID
     * @param opinion 审核意见
     * @param mark    审批通过 audit_pass
     *                审批否决 audit_veto
     *                审批退回 audit_back
     * @return 审核结果
     */
    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public CommonResult audit(String id, String opinion, String mark) {
        ExpRevocation info = expRevocationMapper.getInfo(id);
        String auditState = flowAddAuditUtil.audit(info.getBusinessId(), opinion, mark, null);
        if (StringUtils.isEmpty(auditState)) {
            throw new CourseException(ShiroResultEnum.FAIL.getCode(), MessageEnum.FAIL.getMsg());
        }
        if (!FlowStateEnum.IN_AUDIT.getState().equals(auditState)) {
            //审核结束
            info.setFlowState(auditState);
            info.setModifier(ShiroUserUtil.getUserName());
            int num = expRevocationMapper.updateState(info);
            if (NumberEnum.ZERO.getNum() == num) {
                throw new CourseException(ShiroResultEnum.FAIL.getCode(), MessageEnum.FAIL.getMsg());
            }
            dealResult(auditState, info);
        }
        return CommonResult.ResponseResult(NumberEnum.ONE.getNum());
    }

    /**
     * 处理审核结果
     *
     * @param auditState 审核结果
     * @param info       撤销信息
     */
    private void dealResult(String auditState, ExpRevocation info) {
        ExpPayReq expPayReq = expPayReqMapper.selectByPrimaryKey(info.getBusinessId());
        if (auditState.equals(String.valueOf(NumberEnum.THREE.getNum()))) {
            dealReject(info, expPayReq);
        } else if (FlowStateEnum.PASS.getState().equals(auditState)) {
            dealPass(info, expPayReq);
        }
    }

    /**
     * 处理审核失败
     *
     * @param info      撤销信息
     * @param expPayReq 付款信息
     */
    private void dealReject(ExpRevocation info, ExpPayReq expPayReq) {
        if (String.valueOf(NumberEnum.ONE.getNum()).equals(info.getType())) {
            //项目撤销并且撤销审核不通过
            expProjectReqMapper.changeStep(info.getProjectId(), String.valueOf(NumberEnum.FOUR.getNum()));
        } else if (String.valueOf(NumberEnum.TWO.getNum()).equals(info.getType())) {
            //拨款撤销并且撤销审核不通过
            expPayReqMapper.updateStep(info.getBusinessId(), info.getStep(), null);
            String busiNo = expPayReq.getPayNo();
            if (StringUtils.isNotEmpty(busiNo)) {
                accKeepAccountMapper.updateState(NumStrEnum.ONE.getNum(), busiNo);
            }
        }
    }

    /**
     * 处理审核成功
     *
     * @param info      撤销信息
     * @param expPayReq 付款信息
     */
    private void dealPass(ExpRevocation info, ExpPayReq expPayReq) {
        //审核通过后，更新业务表，分为项目撤销和拨款撤销
        if (NumStrEnum.ONE.getNum().equals(info.getType())) {
            //更新项目表
            ExpProjectReq expProjectReq = new ExpProjectReq();
            expProjectReq.setId(info.getBusinessId());
            expProjectReq.setModifier(ShiroUserUtil.getUserName());
            expProjectReq.setFlowState(String.valueOf(NumberEnum.ZERO.getNum()));
            expProjectReq.setStep(String.valueOf(NumberEnum.TWO.getNum()));
            int count = expProjectReqMapper.updateByPrimaryKeySelective(expProjectReq);
            if (NumberEnum.ZERO.getNum() == count) {
                throw new CourseException(ShiroResultEnum.FAIL.getCode(), MessageEnum.FAIL.getMsg());
            }
        } else if (NumStrEnum.TWO.getNum().equals(info.getType())) {
            //更新拨款表
            expPayReq.setFlowState(String.valueOf(NumberEnum.ZERO.getNum()));
            expPayReq.setStep(String.valueOf(NumberEnum.ZERO.getNum()));
            expPayReq.setModifier(ShiroUserUtil.getUserName());
            int count = expPayReqMapper.updateByPayReqCancel(expPayReq);
            if (NumberEnum.ZERO.getNum() == count) {
                throw new CourseException(ShiroResultEnum.FAIL.getCode(), MessageEnum.FAIL.getMsg());
            }
        }
    }

    /**
     * 查询拨款申请撤销审批列表
     *
     * @param page          分页实体
     * @param expRevocation 查询实体
     * @return 审批列表
     */
    @Override
    public PageInfo<ExpRevocation> getPayAuditList(Page page, ExpRevocation expRevocation) {
        //查询业务
        Map<String, String> map = flowUtil.getBussIdAndZoneCodeByOperNo(FlowTypeEnum.PAY_REVOCATION.getType());
        List<ExpRevocation> list = new ArrayList<>();
        if (null != map) {
            result.select(map, expRevocation);
            PageHelper.startPage(page.getPageNum(), page.getPageSize());
            if (StringUtils.isNotEmpty(expRevocation.getFuzzy())) {
                //模糊查询
                list = expRevocationMapper.fuzzyPayAuditList(expRevocation);
            } else {
                //精确查询
                list = expRevocationMapper.getPayAuditList(expRevocation);
            }
        }
        return new PageInfo<>(list);
    }

    /**
     * 新增撤销记录
     *
     * @param expRevocation 撤销记录实体
     * @param flowState     状态
     * @return
     */
    private CommonResult addExpRevocation(ExpRevocation expRevocation, String flowState,
                                          String grantreqNum, String step, ExpProjectReq expProjectReq) {
        expRevocation.setBusinessId(expRevocation.getId());
        expRevocation.setId(UUIDUtil.getUUID());
        expRevocation.setRegionId(expProjectReq.getRegionId());
        expRevocation.setFlowState(flowState);
        expRevocation.setGrantreqNum(grantreqNum);
        expRevocation.setStep(step);
        expRevocation.setProjectName(expProjectReq.getReqName());
        expRevocation.setReqNo(expProjectReq.getReqNo());

        int insert = expRevocationMapper.insert(expRevocation);
        if (insert == NumberEnum.ZERO.getNum()) {
            throw new CourseException(ShiroResultEnum.FAIL.getCode(), "新增撤销记录失败");
        }
        return CommonResult.ResponseResult(insert);
    }
}
